#include "radiosity.h"

#include "patch.h"
#include "form_factor.h"
#include "gauss_jacobi.h"
#include "material.h"
#include "color.h"

namespace t2c2 {

Radiosity::Radiosity(Scene* _scene) : scene(_scene) , solving_times(100) , shadow(false) {
	
}
Radiosity::~Radiosity(void) {
}

Scene* Radiosity::get_scene(void) const {
	return scene;
}

void Radiosity::set_scene(Scene* _scene) {
	scene = _scene;
}
	
unsigned int Radiosity::get_solving_times(void) const {
	return solving_times;
}
void Radiosity::set_solving_times(const unsigned int _solving_times) {
	solving_times = _solving_times;
}
	
bool Radiosity::get_shadow(void) const {
	return shadow;
}
void Radiosity::set_shadow(bool _shadow) {
	shadow = _shadow;
}
	
void Radiosity::calculate(unsigned int _solving_times, unsigned int _monte_carlo_samples) {
	unsigned int patches = scene->size_patches();
	
	Matrix matrix(patches,patches,IDENTITY_MATRIX);
	Vector e(patches);
	
	Matrix form_factors(patches,patches);

	for(unsigned int i = 0; i < patches; i++) {
		Patch* patch_i = scene->get_patch(i);
		for(unsigned int j = 0; j < patches; j++) {
			if(i == j)  continue;
			Patch* patch_j = scene->get_patch(j);
			form_factors[i][j] = Form_Factor::calculate(patch_i,patch_j,_monte_carlo_samples,scene,shadow);
		}
	}
	
	/* Red */
	
	for(unsigned int i = 0; i < patches; i++) {
		Patch* patch_i = scene->get_patch(i);
		Material* material = patch_i->get_material();
		Color emissivity = material->get_emissivity();
		Color reflectivity = material->get_reflectivity();
		double r_red = reflectivity.red;
		double e_red = emissivity.red;
		
		e[i] = e_red;
		for(unsigned int j = 0; j < patches; j++) {
			if(i == j)  continue;
			matrix[i][j] = -form_factors[i][j]*r_red;
		}
	}
	
	Gauss_Jacobi solver1(&matrix,e);
	
	Vector b_red = solver1.solve(e);
	for(unsigned int k = 0 ; k < _solving_times; k++) {
		b_red = solver1.solve(b_red);
	}
	
	/* Green */
	
	for(unsigned int i = 0; i < patches; i++) {
		Patch* patch_i = scene->get_patch(i);
		Material* material = patch_i->get_material();
		Color emissivity = material->get_emissivity();
		Color reflectivity = material->get_reflectivity();
		double r_green = reflectivity.green;
		double e_green = emissivity.green;
		
		e[i] = e_green;
		for(unsigned int j = 0; j < patches; j++) {
			if(i == j)  continue;
			matrix[i][j] = -form_factors[i][j]*r_green;
		}
	}
	
	Gauss_Jacobi solver2(&matrix,e);
	
	Vector b_green = solver2.solve(e);
	for(unsigned int k = 0 ; k < _solving_times; k++) {
		b_green = solver2.solve(b_green);
	}
	
	/* Blue */
	
	for(unsigned int i = 0; i < patches; i++) {
		Patch* patch_i = scene->get_patch(i);
		Material* material = patch_i->get_material();
		Color emissivity = material->get_emissivity();
		Color reflectivity = material->get_reflectivity();
		double r_blue = reflectivity.blue;
		double e_blue = emissivity.blue;
		
		e[i] = e_blue;
		for(unsigned int j = 0; j < patches; j++) {
			if(i == j)  continue;
			matrix[i][j] = -form_factors[i][j]*r_blue;
		}
	}
	
	Gauss_Jacobi solver3(&matrix,e);
	
	Vector b_blue = solver3.solve(e);
	for(unsigned int k = 0 ; k < _solving_times; k++) {
		b_blue = solver3.solve(b_blue);
	}

	/* Updating radiosity */	

	for(unsigned int i = 0; i < patches ; i++) {
		Material* material = scene->get_patch(i)->get_material();
		material->set_radiosity(Color(b_red[i],b_green[i],b_blue[i]));
	}
}

	
}
